package cn.com.rexen.rplus.security;

import cn.com.rexen.rplus.core.criteria.Criteria;
import cn.com.rexen.rplus.core.criteria.CriteriaFactory;
import cn.com.rexen.rplus.core.utils.StringUtils;
import cn.com.rexen.rplus.sa.entity.Permission;
import cn.com.rexen.rplus.sa.entity.Role;
import cn.com.rexen.rplus.sa.service.PermissionService;
import cn.com.rexen.rplus.sa.service.RoleService;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 取得所有资源及其对应角色的定义.
 *
 * @author libo
 */
@Service(value = "filterInvocationDefinitionSource")
public class FilterInvocationSecurityMetadataSource
        implements
        org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource {

    private final Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());

    private Map<String, Collection<ConfigAttribute>> resourceMap = null;


    /**
     * 权限服务类.
     */
    @Autowired
    private PermissionService permissionService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private CriteriaFactory criteriaFactory;

    @PostConstruct
    public void loadResourceDefine() {
        resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
        Criteria criteria = criteriaFactory.getCriteria(Permission.class);
        List<Permission> permissions = permissionService.find(criteria);
        for (Permission permission : permissions) {
            // 如果是restful风格的应用，则构造方法的参数应该是url和method
            // RequestKey key = new RequestKey(resource.getPath());
            // 参数权限资源ID.与HibernateUserDetailsService.GrantedAuthorityImpl ga =
            // new GrantedAuthorityImpl(ps.getId());中设置的ID是一致的.

            Collection<ConfigAttribute> ca = new ArrayList<ConfigAttribute>();
            List<Role> rs = roleService.getRoleByPermissionId(permission.getId());
            for (Role role : rs) {
                ConfigAttribute attribute = new SecurityConfig(role.getId());
                ca.add(attribute);
            }
            resourceMap.put(StringUtils.connect(permission.getResource().getPath(),  permission.getOperate().getUri()), ca);
        }
        logger.debug("urlMap init successfully. {}", resourceMap);

        // resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
        // Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
        // ConfigAttribute ca = new SecurityConfig("ROLE_ADMIN");
        // atts.add(ca);
        // resourceMap.put("/index.jsp", atts);
        // resourceMap.put("/i.jap", atts);
    }

    // According to a URL, Find out permission configuration of this URL.
    public Collection<ConfigAttribute> getAttributes(Object object)
            throws IllegalArgumentException {
        // guess object is a URL.
        String url = ((FilterInvocation) object).getRequestUrl();
        logger.debug("request url :{},role:{}", url, resourceMap.get(url));
        // return resourceMap.get(url);
        FilterInvocation filterInvocation = (FilterInvocation) object;
        HttpServletRequest request = filterInvocation.getHttpRequest();

        Iterator<String> ite = resourceMap.keySet().iterator();
        while (ite.hasNext()) {
            String resURL = ite.next();
            RequestMatcher requestMatcher = new AntPathRequestMatcher(resURL);
            if (requestMatcher.matches(request)) {
                return resourceMap.get(resURL);
            }
        }
        return null;
    }

    public boolean supports(Class<?> clazz) {
        return true;
    }

    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    public RoleService getRoleService() {
        return roleService;
    }

    public void setRoleService(RoleService roleService) {
        this.roleService = roleService;
    }

    public PermissionService getPermissionService() {
        return permissionService;
    }

    public void setPermissionService(PermissionService permissionService) {
        this.permissionService = permissionService;
    }
}
